package lumis.service.wsrp.consumer.doui;

import java.io.IOException;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Properties;

import lumis.doui.processaction.ProcessActionHandler;
import lumis.doui.source.Source;
import lumis.doui.source.field.ISourceField;
import lumis.portal.PortalException;
import lumis.portal.UnexpectedException;
import lumis.portal.serviceinterface.IServiceInterfaceUrl;
import lumis.service.wsrp.common.WSRPUtils;
import lumis.service.wsrp.consumer.producermanager.ProducerEntityManagerFactory;
import lumis.service.wsrp.consumer.producermanager.ProducerEntityManagerImpl;
import lumis.util.XmlUtil;

import com.sun.portal.wsrp.common.WSRPMBeanException;
import com.sun.portal.wsrp.common.stubs.v2.Lifetime;
import com.sun.portal.wsrp.consumer.admin.mbeans.WSRPConsumer;
import com.sun.portal.wsrp.consumer.common.WSRPConsumerException;
import com.sun.portal.wsrp.consumer.producermanager.ProducerEntity;
import com.sun.portal.wsrp.consumer.producermanager.ProducerEntityManager;


/**
 * {@link ProcessActionHandler} that process the WSRP consumer configuration
 * interface. It has three actions:<br />
 * <ul>
 * <li>
 * {@link #goConfig2()} -> creates a link with the given WSRP producer's WSDL
 * address and redirects user to this link.</li>
 * <li>
 * {@link #createConfiguredProducer()} -> creates a configuration to this
 * service instance.</li>
 * <li>
 * {@link #deleteCurrentConfiguration()} -> deletes current service instance's
 * configuration.</li>
 * </ul>
 * 
 * @version $Revision: 13021 $ $Date: 2011-05-20 14:12:00 -0300 (Fri, 20 May 2011) $
 * @since 5.5.0
 */
public class ConsumerConfigurationInterfaceProcessActionHandler extends ProcessActionHandler<Source<ISourceField>>
{
	private static final String VERSION = "version";
	static final String WSDL_URL_PARAMETER_NAME = "wsdl";
	static final String PARAMETER_REGISTRATION_TYPE = "registrationType";
	static final String PARAMETER_REGISTRATION_HANDLE = "registrationHandle";
	static final String PARAMETER_LIFETIME = "lifetime";
	private static final String CONFIGURATION2_INTERFACE_ID = "lumis.service.wsrp.consumer.consumerconfiguration2";
	private static final String ACTION_GO_CONFIG2 = "goConfig2";
	private static final String ACTION_CREATE_CONFIGURED_PRODUCER = "createConfiguredProducer";
	private static final String ACTION_DELETE_CURRENT_CONFIGURATION = "deletecurrentconfiguration";
	private static final String ACTION_CONFIGURE_REGISTRATION = "configureRegistration";

	public void processAction() throws PortalException
	{
		String actionType = XmlUtil.readAttributeString("actionType", processActionNode);
		if (ACTION_GO_CONFIG2.equals(actionType))
		{
			goConfig2();
		}		
		else if (ACTION_CREATE_CONFIGURED_PRODUCER.equals(actionType))
		{
			createConfiguredProducer();
		}	
		else if (ACTION_DELETE_CURRENT_CONFIGURATION.equals(actionType))
		{
			deleteCurrentConfiguration();
		}
		else if (ACTION_CONFIGURE_REGISTRATION.equals(actionType))
		{
			configureRegistration();
			addDefaultResponse();
		}
	}
	
	private void configureRegistration() throws PortalException
	{	
		Date dateLifetime = getParameter(PARAMETER_LIFETIME, Date.class);
		if(dateLifetime == null)
		{
			throw new PortalException("STR_WSRP_LIFETIME_EMPTY", getResource());
		}
		
		// check if current service instance is configured
		String serviceInstanceId = source.getDouiContext().getRequest().getServiceInstanceConfig().getId();
		ProducerEntityManager producerEntityManager = ProducerEntityManagerFactory.getProducerEntityManager(serviceInstanceId);
		ProducerEntity producerEntity = null;
		
		try
		{
			// get producer entity
			if (!(producerEntityManager.getProducerEntityIds().isEmpty()))
			{
				producerEntity = producerEntityManager.getProducerEntity(producerEntityManager.getProducerEntityIds().iterator().next());
				
				Lifetime lifetime = WSRPUtils.lifetimeTerminationTimeFromDate(dateLifetime);				
				((ProducerEntityManagerImpl) producerEntityManager).setLifetime(producerEntity, lifetime);
			}
		}
		catch (WSRPConsumerException e)
		{
			throw new UnexpectedException(e);
		}		
	}

	private void goConfig2() throws PortalException
	{
		String goConfig2 = getParameter("goConfig2", String.class);
		if (goConfig2 != null && goConfig2.length() > 0)
		{
			// gets the wsdl address and create a link with it as a parameter.
			String wsdlUrl = getParameter(WSDL_URL_PARAMETER_NAME, String.class);

			// verify if the given URL is a valid URL
			WSRPConsumer consumer = new WSRPConsumer();
			try
			{
				consumer.getSupportedVersions(wsdlUrl);
			}
			catch (WSRPMBeanException e)
			{
				throw new PortalException(localize("STR_INVALID_WSRP_WSDL_URL"), e);
			}
			
			IServiceInterfaceUrl url = douiContext.getActionResponse().createPortalURL();
			url.setPageId(douiContext.getRequest().getPageConfig().getId());
			url.setChannelId(douiContext.getRequest().getPageConfig().getChannelId());
			url.setRunTimeServiceInstanceId(douiContext.getRequest().getServiceInstanceConfig().getId());
			url.setRunTimeServiceInterfaceId(CONFIGURATION2_INTERFACE_ID);
			url.setParameter(WSDL_URL_PARAMETER_NAME, wsdlUrl);
			try
			{
				// redirects user to the created link
				douiContext.getActionResponse().sendRedirect(url.toString());
			}
			catch (IOException e)
			{
				throw new UnexpectedException(e);
			}
		}
	}

	private void createConfiguredProducer() throws PortalException
	{
		// gets the wsdl and version of target wsrp producer
		String wsdlUrl = getParameter(WSDL_URL_PARAMETER_NAME, String.class);
		String version = getParameter(VERSION, String.class);
		
		String registrationType = getParameter(PARAMETER_REGISTRATION_TYPE, String.class);
		String registrationHandle = getParameter(PARAMETER_REGISTRATION_HANDLE, String.class);
		registrationHandle = ((registrationHandle == null) || (registrationHandle.trim().equals("")))?null:registrationHandle;
						
		if (wsdlUrl == null || version == null)
		{
			IllegalArgumentException e = new IllegalArgumentException("STR_ALL_FIELDS_ARE_REQUIRED");
			throw new PortalException(e.getMessage(), e);
		}
		
		WSRPConsumer consumer = new WSRPConsumer();
		try
		{
			// creates a configuration for current service instance with given
			// values
			
			if (registrationType.equals("2"))
			{
				// in-band registration
				consumer.createConfiguredProducer(
						douiContext.getRequest().getServiceInstanceConfig().getId(), 
						douiContext.getRequest().getServiceInstanceConfig().getId(),
						wsdlUrl,
						version,
						null,
						Collections.<String, List<String>> emptyMap(),
						new Properties(), // registrationData
						null);
			}
			else
			{
				// out-band and no register registration types
				consumer.createConfiguredProducer(
						douiContext.getRequest().getServiceInstanceConfig().getId(),
						douiContext.getRequest().getServiceInstanceConfig().getId(),
						wsdlUrl,
						version,
						null,
						Collections.<String, List<String>> emptyMap(),
						registrationHandle,
						Collections.<String, Long> emptyMap());
			}
		}
		catch (WSRPMBeanException e)
		{
			throw new PortalException(e.getMessage(), getResource());
		}

		addDefaultResponse();
	}

	private void deleteCurrentConfiguration() throws PortalException
	{
		String doDeletion = getParameter("doDeletion", String.class);
		if (doDeletion != null && doDeletion.length() > 0)
		{
			// deletes current service instance's configuration
			try
			{
				String serviceInstanceId = douiContext.getRequest().getServiceInstanceConfig().getId();
				
				ProducerEntityManager producerEntityManager = 
										ProducerEntityManagerFactory
											.getProducerEntityManager(serviceInstanceId);
				for (String producerEntityId : producerEntityManager.getProducerEntityIds())
				{
					if(isValidRegistration(producerEntityManager, producerEntityId))
					{
						producerEntityManager.removeProducerEntity(producerEntityId, true);
					}
					else
					{
						((ProducerEntityManagerImpl)producerEntityManager).purgeProducerEntity(producerEntityId);						
					}

				}

			}
			catch (WSRPConsumerException e)
			{
				throw new UnexpectedException(e);
			}
		}
	}
	
	/**
	 * Verifies if the producer says the registration is still valid.
	 * @param producerEntityManager manager to execute remote call 
	 * @param producerEntityId producer entity id 
	 * @return true if the service description is updated successfully, false is otherwise.
	 */
	private boolean isValidRegistration(ProducerEntityManager producerEntityManager, String producerEntityId)
	{
		boolean valid = true;
		try
		{
			//verifies if the registration is still valid in producer.
			producerEntityManager.updateServiceDescription(producerEntityId);
		}
		catch (WSRPConsumerException e)
		{
			//there is no specific exception for invalid registration, therefore we (wrongly) assume this exception occurred because of invalid registration.
			//this is the only (inaccurate) way to verify this.
			valid = false;
		}		
		return valid;
	}
}
